#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <stack>
#include <algorithm>
#include <string>
#include <map>
#include <set>
#include <vector>

using namespace std;

#define BEGINS(x) namespace x {
#define ENDS(x) } // end of namespace x

// 自己实现智能指针

BEGINS(test)
class A {
public:
    A() {
        cout << "default constructor" << endl;
    }
    int x, y;
    ~A() {
        cout << "destructor" << endl;
    }
};

class shared_ptr {
public:
    shared_ptr(A *ptr, int *cnt = nullptr) : ptr(ptr) , cnt(cnt) {
        if (ptr != nullptr && cnt == nullptr) {
            this->cnt = new int(1);
        }
    }

    shared_ptr(const shared_ptr &obj) : ptr(obj.ptr), cnt(obj.cnt) {
        (*cnt)++;
    }

    ~shared_ptr() { decrease_one(); }

    A *operator->() { return ptr; }
    A &operator*() { return *ptr; }
    shared_ptr &operator=(const shared_ptr &obj) {
        if (this->ptr == obj.ptr && this->cnt == obj.cnt) return *this;
        decrease_one();
        this->ptr = obj.ptr;
        this->cnt = obj.cnt;
        (*cnt)++;
        return *this;
    }
    // const method
    const A *operator->() const { return ptr; }
    const A &operator*() const { return *ptr; }

    int use_count() { return *cnt; }
private:
    A *ptr;
    int *cnt;
    void decrease_one() {
        (*cnt)--;
        if ((*cnt) == 0) {
            delete ptr;
            delete cnt;
        }

    }
};


ostream &operator<<(ostream &out, const A &obj) {
    out << obj.x << " " << obj.y;
    return out;
}

shared_ptr make_shared() {
    return shared_ptr(new A());
}

int main () {
    shared_ptr p = make_shared();
    p->x = 3, p->y = 4;
    cout << *p << endl;
    cout << "p.use_count = " << p.use_count() << endl;

    shared_ptr q = p;
    cout << "p.use_count = " << p.use_count() << endl;
    cout << "q.use_count = " << q.use_count() << endl;
    p = nullptr;
    cout << "q.use_count = " << q.use_count() << endl;
    q = nullptr;
    cout << "end main" << endl;

    return 0;
}
ENDS(test)

int main() {
    test::main();
    return 0;
}
